<?php

namespace PhpYes\Modules\Cmd;


final class ArgumentAnalyzer
{
    const OptIndicatorShort = '-';
    const OptIndicatorLong = '--';

    const ArgTypeNone = 0;
    const ArgTypeOptShort = 1; // -x...
    const ArgTypeOptLong = 2; // --x...
    const ArgTypePosition = 3; // x...
    const ArgTypeOptIndicatorShort = 4; // -
    const ArgTypeOptIndicatorLong = 5; // --

    /** @var bool */
    private $isAnalyzed;

    /** @var string */
    private $arg;

    /**
     * refer self::ArgTypeXX
     * @var int
     */
    private $argType;

    /**
     * @var string
     */
    private $argName;

    /**
     * @var string
     */
    private $argValue;

    /**
     * ArgObject constructor.
     * @param string $arg
     */
    public function __construct($arg)
    {
        $this->isAnalyzed = false;
        $this->arg = $arg;
        $this->argType = self::ArgTypeNone;
        $this->argName = null;
        $this->argValue = null;
    }

    /**
     * @return string
     */
    public function getArg()
    {
        return $this->arg;
    }

    /**
     * @return int
     */
    public function getArgType()
    {
        if (!$this->isAnalyzed) {
            $this->analyze();
        }

        return $this->argType;
    }

    /**
     * @return string
     */
    public function getArgName()
    {
        if (!$this->isAnalyzed) {
            $this->analyze();
        }

        return $this->argName;
    }

    /**
     * @return string
     */
    public function getArgValue()
    {
        if (!$this->isAnalyzed) {
            $this->analyze();
        }

        return $this->argValue;
    }

    private function analyze()
    {
        if ($this->isAnalyzed) {
            return;
        }
        $this->isAnalyzed = true;

        $arg = trim($this->arg);
        if (empty($arg)) {
            return;
        }

        $firstLetter = $arg[0];
        if ($firstLetter != self::OptIndicatorShort) { // x...
            $this->argType = self::ArgTypePosition;

            return;
        }
        // -...

        $len = strlen($arg);
        if ($len == 1) { // -
            $this->argType = self::ArgTypeOptIndicatorShort;

            return;
        }
        // -... && len > 1

        $secondLetter = $arg[1];
        if ($secondLetter != self::OptIndicatorShort) { // -x...
            $this->argType = self::ArgTypeOptShort;
            $this->argName = substr($arg, 1);

            return;
        }
        // --... && len > 1

        if ($len == 2) { // --
            $this->argType = self::ArgTypeOptIndicatorLong;

            return;
        }
        // --... && len > 2

        $thirdLetter = $arg[2];
        if ($len == 3) {
            $this->argType = self::ArgTypeOptLong;
            $this->argName = $thirdLetter;

            return;
        }
        // --... && len > 3

        $this->argType = self::ArgTypeOptLong;
        $pos = strpos($arg, '=', 3);
        if ($pos) {
            $this->argName = substr($arg, 2, $pos - 2);
            $val = substr($arg, $pos + 1);
            if (empty($val)) {
                $val = '';
            }
            $this->argValue = $val;
        } else {
            $this->argName = substr($arg, 2);
        }
    }

    public static function test()
    {
        $letterArr = ['-', '=', '#', 'x'];
        $last = $letterArr;
        $next = array();
        $caseArr = $letterArr;
        for ($i = 1; $i < 5; $i++) {

            foreach ($last as $str) {
                foreach ($letterArr as $letter) {
                    $next[] = $str . $letter;
                }
            }
            $last = $next;
            $next = array();

            $caseArr = array_merge($caseArr, $last);
        }

        $result = array();
        foreach ($caseArr as $arg) {
            $argObj = new ArgumentAnalyzer($arg);
            $argDesc = ['argType' => '', 'argName' => $argObj->getArgName(), 'argVal' => $argObj->getArgValue()];

            switch ($argObj->getArgType()) {
                case self::ArgTypeNone:
                    $argDesc['argType'] = 'ArgTypeNone';
                    break;
                case self::ArgTypeOptShort:
                    $argDesc['argType'] = 'ArgTypeOptShort';
                    break;
                case self::ArgTypeOptLong:
                    $argDesc['argType'] = 'ArgTypeOptLong';
                    break;
                case self::ArgTypePosition:
                    $argDesc['argType'] = 'ArgTypeArg';
                    break;
                case self::ArgTypeOptIndicatorShort:
                    $argDesc['argType'] = 'ArgTypeOptIndicatorShort';
                    break;
                case self::ArgTypeOptIndicatorLong:
                    $argDesc['argType'] = 'ArgTypeOptIndicatorLong';
                    break;
                default:
                    $argDesc['argType'] = 'ArgTypeError';
                    break;
            }
            $result[$arg] = $argDesc;
        }
        echo json_encode($result);
    }

}